#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>


enum state {ST_BEFORE_KEY, ST_IN_KEY, ST_BEFORE_VALUE, ST_IN_VALUE, ST_TERM, ST_ERR};

typedef enum state state;
typedef struct {
  state st; 
  struct {
    char bytes[100];
    int current;
    int escape;
  } data;
} tSM;

typedef struct {
  state st;
  state (*fn)(char, tSM *);
} tTransition;

static state TrimSpace(char, tSM*);
static state GotKey(char, tSM*);
static state GotValue(char, tSM*);
static state ErrorProcess(char, tSM*);

tTransition trans[] = {
	{ST_BEFORE_KEY, TrimSpace},
	{ST_IN_KEY, GotKey},
	{ST_BEFORE_VALUE, TrimSpace},
	{ST_IN_VALUE, GotValue},
	{ST_ERR, ErrorProcess}
};

#define TRANS_COUNT (sizeof(trans)/sizeof(*trans))


int AddChar(char c, tSM* sm, char delim)
{
  if('\0' == c){
    return 2;
  }
  if(sm->data.escape){
    sm->data.escape = 0;
    if(c == delim){
      sm->data.bytes[sm->data.current-1] = c;
    }
    else{
      sm->data.bytes[sm->data.current] = c;
      sm->data.current++;
    }
  }
  else{
    if(c == '\\'){
      sm->data.escape = 1;
      sm->data.bytes[sm->data.current] = c;
      sm->data.current++;
    }
    else if(c == delim){
      return 1;
    }
    else{
      sm->data.bytes[sm->data.current] = c;
      sm->data.current++;
    }
  }
  return 0;
}

state TrimSpace(char c, tSM* sm)
{
  if(c == ' ' || c == '\n' || c == '\t' || c == '\r')
  {
     return sm->st; 
  }
  else
  {
    if('\0' == c){
      return ST_TERM;
    }
    sm->data.bytes[sm->data.current] = c;
    sm->data.current++;
    switch(sm->st)
    {
      case ST_BEFORE_KEY:
        return ST_IN_KEY;
      case ST_BEFORE_VALUE:
        return ST_IN_VALUE;
      default:
        return ST_ERR;
    }
  }
}

state GotKeyOrValue(char c, tSM* sm, char delim)
{
  int ret = AddChar(c, sm, delim);
  if(ret == 1 || ret == 2)
  {
    //delimiter meti,change state
    switch(sm->st)
    {
      case ST_IN_VALUE:
        sm->data.bytes[sm->data.current] = '\0';
        printf("Finished pasing value:%s\n", sm->data.bytes);
		sm->data.current = 0;
		sm->data.bytes[sm->data.current] = '\0';
        return ret == 2 ? ST_TERM : ST_BEFORE_KEY;
      case ST_IN_KEY:
        sm->data.bytes[sm->data.current] = '\0';
        printf("Finished pasing key:%s\n", sm->data.bytes);
		sm->data.current = 0;
        sm->data.bytes[sm->data.current] = '\0';
        return ret == 2 ? ST_TERM : ST_BEFORE_VALUE;
      default:
        return ST_ERR;
    }
  }
  else
  {
    return sm->st;
  }
}

char delim_k = ':',delim_v = '&';

state GotKey(char c, tSM* sm)
{
  return GotKeyOrValue(c, sm, delim_k);
}

state GotValue(char c, tSM* sm)
{
  return GotKeyOrValue(c, sm, delim_v);
}

state ErrorProcess(char c, tSM* sm)
{
  sm->data.bytes[sm->data.current] = '\0';
  printf("Error happend when parsing %c\n", c);
  printf("Bytes in stack:%s\n", sm->data.bytes);
  return ST_TERM;
}


void ParseOpts(int argc, char* argv[])
{
  int c;
  while((c = getopt(argc, argv, "k:v:")) != -1){
    switch(c){
      case 'k':
        delim_k = optarg[0];
	break;
      case 'v':
		delim_v = optarg[0];
    }
  }
}

int main(int argc, char* argv[])
{
  tSM sm;
  int i = 0;
  int j;
  int length;  
  char c;
  char* querystring;
  ParseOpts(argc, argv);
  printf("delim_k:\t%c\ndelim_v:\t%c\noptind:\t%d\nargc:\t%d\n", delim_k, delim_v, optind, argc);
  if(argc - optind != 1){
    printf("Usage: %s [options] querystring\n", argv[0]);
    return 0;
  }
  querystring = argv[argc - 1];
  length = strlen(querystring);
  printf("querystring:\t%s\nlength:\t%d\n", querystring, length);
  sm.data.escape = 0;
  sm.data.current = 0;
  sm.st = ST_BEFORE_KEY;
  while(sm.st != ST_TERM){
    c = i < length ? querystring[i++] : '\0';
    for(j = 0; j < TRANS_COUNT; j++){
      if(trans[j].st == sm.st){
        sm.st = (trans[j].fn)(c, &sm);
        break;
      }
    }
  }
  return 0;
}
